home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
E.M.Computergraphic Phase 4
/
Phase 4 - Desktop Video Dreams (E. M. Computergraphic)(1996).iso
/
utilities
/
multiplay
/
noteplayer
/
notehard.asm
< prev
next >
Wrap
Assembly Source File
|
1996-01-03
|
7KB
|
248 lines
* notehard.asm - NotePlayer that directly uses the Amiga audio hardware
* Copyright 1992 Bryan Ford
* See distribution terms in NotePlayer.doc
* $Id: notehard.asm,v 1.1 92/05/15 15:08:26 BAF Exp $
include "exec/types.i"
include "hardware/custom.i"
include "hardware/dmabits.i"
include "bry/macros.i"
VERSION equ 1 ; Version of Player.doc this NotePlayer is written for
REVISION equ 0
CLOCK equ 3579545
CUSTOM equ $dff000
code text
*** NoteHard - Jump table providing the hardware NotePlayer interface
xdef NoteHard,_NoteHard
NoteHard
_NoteHard
jmp noteinfo(pc)
jmp noteinit(pc)
jmp notefinish(pc)
jmp notestart(pc)
jmp notestop(pc)
jmp notefreqvol(pc)
jmp notefreq(pc)
jmp notevol(pc)
*** NoteHardDMACall - Pointer to routine client needs to call after about 7 scanlines, or NULL
xdef NoteHardDMACall,_NoteHardDMACall
NoteHardDMACall
_NoteHardDMACall
ds.l 1
*** noteinfo - Return information about this note player
noteinfo
lea \noteinfo(pc),a0
move.l a0,d0
rts
\noteinfo
dc.b VERSION
dc.b REVISION
dc.b 3 ; NOTEF_CHIPSAMPLES!NOTEF_PERIOD
dc.b 4
dc.l \noteplayername
\noteinfoend
\noteplayername dc.b "Amiga hardware NotePlayer",0
even
*** noteinit - Initialize the note player
* d0.b = Number of channels needed (1-128) (ignored)
* a0 = Stereo orientation (ignored)
* Returns: d0 = Zero if successful, pointer to error message on failure
noteinit
moveq #0,d0
; fall through...
*** notefinish - Shut down the note player
notefinish
lea CUSTOM,a0
move.w #DMAF_AUDIO,dmacon(a0)
clr.w aud0+ac_dat(a0)
clr.w aud1+ac_dat(a0)
clr.w aud2+ac_dat(a0)
clr.w aud3+ac_dat(a0)
rts
*** findchan - Find hardware channel address
* d2.b = Channel number
* Returns:
* a1 = Channel address
* a0/d0 = Saved
findchan
moveq #0,d1
move.b d2,d1
lsl.w #4,d1
lea CUSTOM+aud0,a1
adda.w d1,a1
rts
*** notestop - Stop any currently playing note in a channel
* May be called from interrupt code level 4 or lower
* d2.b = Channel number
notestop
moveq #0,d0
moveq #0,d1
; fall through...
*** notestart - Start playing a note immediately
* May be called from interrupt code level 4 or lower
* d2.b = Channel number
* a0 = One-shot sample data
* d0.l = One-shot sample length (0 if no one-shot part)
* a1 = Repeat sample data
* d1.l = Repeat sample length (0 if no repeat part)
* d3.w = Sample frequency (if 0, then high word contains period)
* d4.w = Volume at which to play sample (0-$100)
notestart
move.l a1,-(sp)
move.w d1,-(sp)
or.w d0,d1 ; See if we're just turning the note off
bz \noteoff
bsr findchan
bsr calcper
bsr calcvol
lsr.w #1,d0 ; Stuff the one-shot pointers
bnz \hasoneshot
moveq #2,d0
sub.l a0,a0
\hasoneshot
move.l a0,ac_ptr(a1)
move.w d0,ac_len(a1)
moveq #0,d0 ; Turn DMA for this channel off
bset d2,d0
move.w d0,CUSTOM+dmacon
move.w (sp)+,d1 ; Find repeat part (a1/d1.w)
move.l (sp)+,a1
lsr.w #1,d1
bnz \hasrepeat
moveq #2,d1
sub.l a1,a1
\hasrepeat
lea \dmaflags(pc),a0 ; Save the information we'll need later
or.w d0,(a0)
move.b d2,d0
add.w d0,d0
move.w d1,\repeatlen-\dmaflags(a0,d0.w)
add.w d0,d0
move.l a1,\repeatptr-\dmaflags(a0,d0.w)
lea \dma1(pc),a0 ; Client will call us back after about 7 scanlines
move.l a0,NoteHardDMACall ; -\dmaflags(a0) FIXME
rts
\dma1
move.w #DMAF_SETCLR,d0 ; Turn DMA on
or.w \dmaflags(pc),d0
move.w d0,CUSTOM+dmacon
lea \dma2(pc),a0 ; Wait another 7 scanlines or so
move.l a0,NoteHardDMACall
rts
\dma2
lea CUSTOM,a0 ; Set the repeat pointers
move.w \dmaflags(pc),d0
lsr.w #1,d0
bcc \dmano0
move.l \repeatptr+4*0(pc),aud0+ac_ptr(a0)
move.w \repeatlen+2*0(pc),aud0+ac_len(a0)
\dmano0
lsr.w #1,d0
bcc \dmano1
move.l \repeatptr+4*1(pc),aud1+ac_ptr(a0)
move.w \repeatlen+2*1(pc),aud1+ac_len(a0)
\dmano1
lsr.w #1,d0
bcc \dmano2
move.l \repeatptr+4*2(pc),aud2+ac_ptr(a0)
move.w \repeatlen+2*2(pc),aud2+ac_len(a0)
\dmano2
lsr.w #1,d0
bcc \dmano3
move.l \repeatptr+4*3(pc),aud3+ac_ptr(a0)
move.w \repeatlen+2*3(pc),aud3+ac_len(a0)
\dmano3
clr.l NoteHardDMACall
clr.w \dmaflags
rts
\dmaflags ds.w 1
\repeatlen ds.w 4
\repeatptr ds.l 4
\noteoff
addq #6,sp
moveq #0,d0 ; Turn DMA for this channel off
bset d2,d0
move.w d0,CUSTOM+dmacon
rts
*** calcper - Calculate period and insert it in an IOAudio
* a1 = Hardware channel
* d3.l = Frequency/period value
* a0/a1/d0 = Saved
calcper
tst.w d3
bnz \freq
swap d3
move.w d3,ac_per(a1)
swap d3
rts
\freq
move.l #CLOCK,d1
divu.w d3,d1
move.w d1,ac_per(a1)
rts
*** calcvol - Calculate volume and insert it in an IOAudio
* a1 = Hardware channel
* d4.w = Volume (0-$100)
* a0/a1/d0 = Saved
calcvol
move.w d4,d1
lsr.w #2,d1
move.w d1,ac_vol(a1)
rts
*** notefreqvol - Change the frequency and volume of the currently playing note
* May be called from interrupt code level 4 or lower
* d2.b = Channel number
* d3.w = New sample frequency (if 0, then high word contains period)
* d4.w = New volume (0-$100)
notefreqvol
bsr findchan
bsr calcper
bra calcvol
*** notefreq - Change the frequency of the currently playing note
* May be called from interrupt code level 4 or lower
* d2.b = Channel number
* d3.w = New sample frequency (if 0, then high word contains period)
notefreq
bsr findchan
bra calcper
*** notevol - Change the volume of the currently playing note
* May be called from interrupt code level 4 or lower
* d2.b = Channel number
* d4.w = New volume (0-$100)
notevol
bsr findchan
bra calcvol
end